Categories: Flex; Tagged with: ActionScript • AIR • Drag and Drop • Flex; @ September 29th, 2008 23:25[小站博客均为原创, 转载请保留以下信息:
作者:http://liguoliang.com 欢迎访问:Adobe上海用户组: http://riashanghai.com ]
关于Drag和Drop的基础知识与基本应用可以参见:http://livedocs.adobe.com/flex/3/html/help.html?content=dragdrop_1.html
1. 设计目标
实现Flex/AIR中的Tree,DataGrid自身或相互之间的拖动.
本例仍旧使用NoteManagement,关于NoteManagement的相关信息请参见:
1.完整Flex程序+详细解释之便条管理系统(Tree/回溯/XML/Event) Annotated Flex Sample Application: Note Management
2.使用Air与SQLite开发NoteManagement
3.Flex树形菜单动态加载 Flex Tree Dynamic Loading
通过以上三篇文章,您将对NoteManagement有一个概括性的了解.
2.概要设计:
2.1 Tree内目录拖动的实现:
如果使用Tree自带的Drag与Drop属性设定Tree,则目录之间只能实现十分局限的拖 动,如果目录不含有子目录,则其他目录无法拖动到该目录下.要解决这个问题,就必须使用自定义的itemRenderer,该itemRenderer继 承自TreeItemRenderer从而不影响Tree的其他功能的正常使用,相对来说,自定义的itemRenderer应该具有以下功能:1.在有 目录drag到itemRenderer上时他能够acceptDragDrop. 2:可以接受并处理dragDrop事件.
2.2 Note移动的实现:
使用DataGrid的属性dragEnabled属性设定DataGrid可以被drag. 当drag到目录中时,dragEnter的target acceptDragDrop,通过对相关事件的监听进行相应处理.
3.详细实现:
3.1 Tree内目录拖动:
设置Tree的属性为:dragEnabled=”true” dropEnabled=”false”
在Tree初始化完成后监听DRAG_COMPLETE事件;DragtreeCategory.addEventListener(DragEvent.DRAG_COMPLETE, onCatDragComplete);
通过使用onCatDragComplete可以阻止其默认行为preventDefault(),这样我们获得对DRAG_DROP的控制.
为 Tree建立一个自定义的itemRenderer,该itemRenderer监听DragEvent.DRAG_ENTER与 DragEvent.DRAG_DROP,通过对DRAG_ENTER的监听,控制itemRenderer是否接受Drag,通过对DRAG_DROP 的监听,将DRAG的目录加入到DROP目录中,并删除原目录,以完成整个过程.
3.2 Note的移动
设置DataGrid的属性为dragEnabled=”true”
同3.1在DataGrid初始化完成后监听DRAG_Complete,阻止默认行为并获得控制
当Drag的Note Enter到Tree中时,通过itemRenderer的监听, 控制itemRenderer是否接受DragDROP,并控制后续过程.
自定义itemRenderer的代码如下:
- package component
- {
- import com.insprise.common.sql.Connection;
- import com.insprise.common.utility.LogUtils;
- import com.insprise.common.utility.SQLUtils;
- import com.insprise.nmair.Category;
- import com.insprise.nmair.Note;
-
- import flash.data.SQLConnection;
- import flash.events.SQLEvent;
-
- import mx.controls.treeClasses.TreeItemRenderer;
- import mx.events.DragEvent;
- import mx.managers.DragManager;
-
- public class TreeCatItemRender extends TreeItemRenderer
- {
- public static var dragAndDropClass:int;
-
- private var conn:SQLConnection = new SQLConnection();
- private var catMoved:Category;
- private var catMoveInto:Category;
- private var catEnter:Category;
- private var noteMoved:Note;
- private var noteMoveIntoCat:Category;
- private var noteEnter:Category;
-
-
-
- public function TreeCatItemRender() {
- super();
- this.addEventListener(DragEvent.DRAG_ENTER, dragEnterHandler);
- this.addEventListener(DragEvent.DRAG_DROP, dragDropHandler);
- }
-
-
- private function dragEnterHandler(e:DragEvent):void {
- if(e.dragSource.hasFormat(“treeItems”)) {
- dragAndDropClass = 0;
- catMoved = e.dragSource.dataForFormat(“treeItems”)[0] as Category;
- catEnter = this.data as Category;
- LogUtils.defaultLog.info(“Draged Item: “ + catMoved.label);
- LogUtils.defaultLog.info(“Enter Cat: “ + catEnter.label);
- if(catMoved.isAncestor(catEnter) || catMoved == catEnter || catMoved.parent == catEnter) {
- LogUtils.defaultLog.info(“上级目录不可移动到下级目录, 也不可移动到期自身内部”);
- return;
- }
- DragManager.acceptDragDrop(e.currentTarget as TreeCatItemRender);
- }
-
- else if(e.dragSource.hasFormat(“items”)) {
- dragAndDropClass = 1;
- noteMoved = e.dragSource.dataForFormat(“items”)[0] as Note;
- noteEnter = this.data as Category;
- if(noteMoved.parent == noteEnter) {
- LogUtils.defaultLog.info(“没有进行移动,不进行任何操作”);
- return;
- }
- DragManager.acceptDragDrop(this);
- trace(“Note parent.id: “ + noteMoved.parent.id );
- trace(” Note Enter Cat id: “ + noteEnter.id);
- }
- }
-
-
- private function dragDropHandler(e:DragEvent):void {
- if(dragAndDropClass == 0) {
- e.preventDefault();
- catMoveInto = this.data as Category;
- LogUtils.defaultLog.info(“移动进: “ + catMoveInto.label);
- }
- else if(dragAndDropClass == 1) {
- e.preventDefault();
- noteMoveIntoCat = this.data as Category;
- LogUtils.defaultLog.info(“Note: “ + noteMoved.title + ” 被拖进了: “ + noteMoveIntoCat.label);
- }
-
- if(conn.connected) {
- LogUtils.defaultLog.info(“DataBase have Connected. Call UpdateDB Directly”);
- updateDB();
- return;
- }
- LogUtils.defaultLog.info(“Connect Db…..”);
- conn.addEventListener(SQLEvent.OPEN, updateDB);
- conn.openAsync(Connection.dbFile);
- }
-
- private function updateDB(e:SQLEvent=null):void {
- if(dragAndDropClass == 0) {
- var updateCatSql:String = “UPDATE Cat SET parent_ID='” + catMoveInto.id + “‘ WHERE cat_ID
- =” + catMoved.id;
- SQLUtils.createAndExecuteStatement(conn, updateCatSql, null, updateDBSucess)
- }
- else if(dragAndDropClass == 1) {
- var updateNotesql:String = “UPDATE Note SET parent_ID='” + noteMoveIntoCat.id +
- “‘ WHERE note_ID=” + noteMoved.id;
- SQLUtils.createAndExecuteStatement(conn, updateNotesql, null, updateDBSucess)
- }
- }
-
-
- private function updateDBSucess(e:SQLEvent):void {
- if(dragAndDropClass == 0) {
- LogUtils.defaultLog.info(catMoved.label + ” 的parent_ID已成功更新为: “ + catMoveInto.id);
- catMoveInto.addSubCat(catMoved);
- LogUtils.defaultLog.info(“目录: “ + catMoveInto.label + ” 成功添加子目录: “ + catMoved.label);
- }
- else if(dragAndDropClass == 1) {
- LogUtils.defaultLog.info(noteMoved.title + “的parent_ID已成功更新为: “ + noteMoveIntoCat.id);
- noteMoveIntoCat.addNote(noteMoved);
- LogUtils.defaultLog.info(“目录: “ + noteMoveIntoCat.label + ” 成功添加Note: “ + noteMoved.title);
- }
- }
-
- }
- }
package component
{
import com.insprise.common.sql.Connection;
import com.insprise.common.utility.LogUtils;
import com.insprise.common.utility.SQLUtils;
import com.insprise.nmair.Category;
import com.insprise.nmair.Note;
import flash.data.SQLConnection;
import flash.events.SQLEvent;
import mx.controls.treeClasses.TreeItemRenderer;
import mx.events.DragEvent;
import mx.managers.DragManager;
public class TreeCatItemRender extends TreeItemRenderer
{
public static var dragAndDropClass:int; //辨别Drag来自于Tree还是DataGrid.
private var conn:SQLConnection = new SQLConnection();
private var catMoved:Category;
private var catMoveInto:Category;
private var catEnter:Category;
private var noteMoved:Note;
private var noteMoveIntoCat:Category;
private var noteEnter:Category;
/**
* 构造函数,每次使用该Renderer时会自动添加EventListener;
*/
public function TreeCatItemRender() {
super();
this.addEventListener(DragEvent.DRAG_ENTER, dragEnterHandler);
this.addEventListener(DragEvent.DRAG_DROP, dragDropHandler);
}
//在拖动到某一个Render上时,判断是否允许接受Drop;
private function dragEnterHandler(e:DragEvent):void {
if(e.dragSource.hasFormat("treeItems")) {
dragAndDropClass = 0;
catMoved = e.dragSource.dataForFormat("treeItems")[0] as Category;
catEnter = this.data as Category;
LogUtils.defaultLog.info("Draged Item: " + catMoved.label);
LogUtils.defaultLog.info("Enter Cat: " + catEnter.label);
if(catMoved.isAncestor(catEnter) || catMoved == catEnter || catMoved.parent == catEnter) {
LogUtils.defaultLog.info("上级目录不可移动到下级目录, 也不可移动到期自身内部");
return;
}
DragManager.acceptDragDrop(e.currentTarget as TreeCatItemRender);
}
else if(e.dragSource.hasFormat("items")) {
dragAndDropClass = 1;
noteMoved = e.dragSource.dataForFormat("items")[0] as Note;
noteEnter = this.data as Category;
if(noteMoved.parent == noteEnter) {
LogUtils.defaultLog.info("没有进行移动,不进行任何操作");
return;
}
DragManager.acceptDragDrop(this);
trace("Note parent.id: " + noteMoved.parent.id );
trace(" Note Enter Cat id: " + noteEnter.id);
}
}
//在Drop之后 ,建立与数据库的连接,准备更新数据库.
private function dragDropHandler(e:DragEvent):void {
if(dragAndDropClass == 0) {
e.preventDefault();
catMoveInto = this.data as Category;
LogUtils.defaultLog.info("移动进: " + catMoveInto.label);
}
else if(dragAndDropClass == 1) {
e.preventDefault();
noteMoveIntoCat = this.data as Category;
LogUtils.defaultLog.info("Note: " + noteMoved.title + " 被拖进了: " + noteMoveIntoCat.label);
}
if(conn.connected) {
LogUtils.defaultLog.info("DataBase have Connected. Call UpdateDB Directly");
updateDB();
return;
}
LogUtils.defaultLog.info("Connect Db.....");
conn.addEventListener(SQLEvent.OPEN, updateDB);
conn.openAsync(Connection.dbFile);
}
//建立 与数据的 连接之后Update改纪录.
private function updateDB(e:SQLEvent=null):void {
if(dragAndDropClass == 0) {
var updateCatSql:String = "UPDATE Cat SET parent_ID='" + catMoveInto.id + "' WHERE cat_ID=" + catMoved.id;
SQLUtils.createAndExecuteStatement(conn, updateCatSql, null, updateDBSucess)
}
else if(dragAndDropClass == 1) {
var updateNotesql:String = "UPDATE Note SET parent_ID='" + noteMoveIntoCat.id + "' WHERE note_ID=" + noteMoved.id;
SQLUtils.createAndExecuteStatement(conn, updateNotesql, null, updateDBSucess)
}
}
//Update成功后,移动目录或note
private function updateDBSucess(e:SQLEvent):void {
if(dragAndDropClass == 0) {
LogUtils.defaultLog.info(catMoved.label + " 的parent_ID已成功更新为: " + catMoveInto.id);
catMoveInto.addSubCat(catMoved);
LogUtils.defaultLog.info("目录: " + catMoveInto.label + " 成功添加子目录: " + catMoved.label);
}
else if(dragAndDropClass == 1) {
LogUtils.defaultLog.info(noteMoved.title + "的parent_ID已成功更新为: " + noteMoveIntoCat.id);
noteMoveIntoCat.addNote(noteMoved);
LogUtils.defaultLog.info("目录: " + noteMoveIntoCat.label + " 成功添加Note: " + noteMoved.title);
}
}
}
}
在move情况下,我们把目标加入到Drop target中,并从Drag initiator中删除,使用dragDrop事件的监听函数来加入目标到Drop target, 使用dragComplete事件的监听函数来删除drag initiator中的源数据.
在这个例子中,由于在 addCat()与addNote()中以含有删除功能,故我们阻止了dragComplete,使用dragDrop处理增加与删除.addCat() 与addNote通过判断源数据的parent是否等于Drop target的id来进行对应处理.
在移动后元数据的parent与Drop target中的Category是不同的,这种情况下先将其删除,修改其parent属性后再加入到Drop target的Category中.完成操作.
代码如下:
-
-
-
-
- public function addSubCat(child:Category):void {
- if(this.subCats == null) {
- subCats = new ArrayCollection();
- }
-
- if(child.parent == null) {
- child._parent = this;
- subCats.addItem(child);
- }else{
- if(child.parent == this) {
- throw new Error(“The parent has already been set to this: “ + toString() + “, child: “ + child);
- }else{
- child._parent.delCat(child);
- child._parent = this;
- subCats.addItem(child);
- }
- }
- }
-
-
-
-
-
-
- public function delCat(child:Category):void {
- trace(“This.id: “ + this.id);
- trace(“child’s Parent ID: “ + child.parent.id);
- trace(child._parent.subCats.getItemIndex(child));
- if(child._parent != this) {
- throw new Error(“The parent of the child is not this: “ + toString() + “, child: “ + child);
- }
-
- subCats.removeItemAt(subCats.getItemIndex(child));
- child._parent = null;
- }
-
-
-
-
-
-
-
-
- public function addNote(note:Note):void {
- if(notes == null) {
- notes = new ArrayCollection();
- } else if(note.parent == null) {
- note.parent = this;
- notes.addItem(note);
- } else{
- if(note.parent == this) {
- throw new Error(note.title + ” 的parent已经被设定为” + this.label);
- } else{
- note.parent.delNote(note);
- note.parent = this;
- notes.addItem(note);
- }
- }
- }
-
-
-
-
-
-
-
- public function delNote(note:Note):void {
- if(note.parent != this) {
- throw new Error(note.title + ” note的parent不是this “ + this.label);
- }
- notes.removeItemAt(notes.getItemIndex(note));
- note.parent = null;
- }
Flex中Event与Bindable <-> Flex Singleton Pattern—-Flex中的单例模式